package com.codingchili.instance.context;

import com.codingchili.instance.model.afflictions.AfflictionDB;
import com.codingchili.instance.model.dialog.DialogDB;
import com.codingchili.instance.model.entity.EntityDB;
import com.codingchili.instance.model.npc.NpcDB;
import com.codingchili.instance.model.questing.QuestDB;
import com.codingchili.instance.model.skills.HarvestDB;
import com.codingchili.instance.model.skills.SkillDB;
import com.codingchili.instance.model.spells.SpellDB;
import com.codingchili.instance.scripting.ScriptReference;
import com.codingchili.realm.model.ClassDB;
import io.vertx.core.Future;
import io.vertx.core.Promise;

import java.util.concurrent.*;

import com.codingchili.core.context.CoreContext;

/**
 * Runs initialization tasks required for the deployment of instances such as loading configuration
 * required by all instances and compiling scripts.
 */
public class InstancesBootstrap {
    private static final int N_THREADS = 12;
    private static final int INIT_TIMEOUT = 10;

    /**
     * Attempts to initialize configurable subsystems.
     *
     * @param core the corecontext to initialize on.
     * @return future
     */
    public static Future<Void> bootstrap(CoreContext core) {
        var promise = Promise.<Void>promise();

        core.<Void>blocking(blocking -> {
            ExecutorService service = Executors.newFixedThreadPool(N_THREADS);
            service.submit(() -> ScriptReference.initialize(core));
            service.submit(() -> new NpcDB(core));
            service.submit(() -> new EntityDB(core));
            service.submit(() -> new SpellDB(core));
            service.submit(() -> new ClassDB(core));
            service.submit(() -> new AfflictionDB(core));
            service.submit(() -> new DialogDB(core));
            service.submit(() -> new SkillDB(core));
            service.submit(() -> new HarvestDB(core));
            service.submit(() -> new SkillDB(core));
            service.submit(() -> new QuestDB(core));
            try {
                service.shutdown();
                service.awaitTermination(INIT_TIMEOUT, TimeUnit.SECONDS);
                blocking.complete();
            } catch (Exception e) {
                blocking.fail(e);
            }
        }, promise::handle);

        return promise.future();
    }

}

